package net.jgrm.product.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import net.jgrm.product.entity.Product;
import net.jgrm.product.service.IProductService;
import net.jgrm.product.service.IProductViewService;
import net.jgrm.product.service.impl.ProductBaseInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * 商品服务控制器
 */
@RestController
@RequestMapping("/api/products")
public class ProductController {

    @Autowired
    private IProductService productService;

    @Autowired
    private IProductViewService productViewService;

    @Autowired
    private ProductBaseInfoService productBaseInfoService;

    /**
     * 根据ID查询商品
     * 同时记录商品访问的PV和UV统计
     */
    @GetMapping("/{id}")
    @SentinelResource(
            value = "api_getProductById",
            blockHandler = "getProductByIdBlockHandler", // 限流处理
            fallback = "getProductByIdFallback" // 降级处理
    )
    public Product getProductById(@PathVariable Long id, HttpServletRequest request) {

        try {
            // 获取商品信息
            Product product = productBaseInfoService.getCompleteProductInfo(id);

            if (product != null) {
                // 检查是否需要记录访问统计（排除管理端访问）
                if (shouldRecordVisit(request)) {
                    recordProductView(id, request);
                }
            }
            return product;
        } catch (Exception e) {
            System.out.println("==============>");
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 限流的处理，方法要与原接口的方法的参数一致
     *
     * @param id
     * @param request
     * @param e
     * @return
     */
    public Product getProductByIdBlockHandler(@PathVariable Long id, HttpServletRequest request, BlockException e) {
        System.err.println("限流处理 - 获取商品失败========> id: " + id + ", 异常: " + e.getClass().getSimpleName());
        e.printStackTrace();

        Product errorProduct = new Product();
        errorProduct.setId(id != null ? id : 0L);
        errorProduct.setProductName("当前请求人数过多，请稍后再试");
        return errorProduct;
    }

    // 熔断降级处理 - 查询商品 (修正后的完整版本)
    public Product getProductByIdFallback(@PathVariable Long id, HttpServletRequest request, Throwable t) {
        System.err.println("熔断处理 - 获取商品失败========> id: " + id + ", 异常: " + t.getClass().getSimpleName());
        t.printStackTrace();

        Product errorProduct = new Product();
        errorProduct.setId(id != null ? id : 0L);
        errorProduct.setProductName("服务暂时不可用，请稍后再试");
        return errorProduct;
    }


    /**
     * 扣减库存
     */
    @PostMapping("/{id}/decrease-stock")
    @SentinelResource(value = "api_decreaseStock", blockHandler = "decreaseStockBlockHandler")
    public boolean decreaseStock(@PathVariable Long id,
                                 @RequestParam Integer quantity) {
        return productService.decreaseStock(id, quantity);
    }

    // 限流处理 - 扣减库存 (修正签名)
    public boolean decreaseStockBlockHandler(@PathVariable Long id,
                                             @RequestParam Integer quantity,
                                             BlockException e) {
        System.err.println("限流处理 - 扣减库存失败========> id: " + id + ", quantity: " + quantity);
        e.printStackTrace();

        return false; // 限流时返回扣减失败
    }


    /**
     * 获取商品访问统计信息
     */
    @GetMapping("/{id}/stats")
    public Map<String, Object> getProductViewStats(@PathVariable Long id) {
        return productViewService.getProductViewStats(id);
    }

    /**
     * 获取商品今日访问统计
     */
    @GetMapping("/{id}/stats/today")
    public Map<String, Object> getTodayProductViewStats(@PathVariable Long id) {
        return productViewService.getTodayProductViewStats(id);
    }

    /**
     * 批量获取商品PV统计
     */
    @PostMapping("/stats/pv/batch")
    public Map<Long, Long> getBatchProductPV(@RequestBody List<Long> productIds) {
        return productViewService.getBatchProductPV(productIds.toArray(new Long[0]));
    }

    /**
     * 批量获取商品UV统计
     */
    @PostMapping("/stats/uv/batch")
    public Map<Long, Long> getBatchProductUV(@RequestBody List<Long> productIds) {
        return productViewService.getBatchProductUV(productIds.toArray(new Long[0]));
    }

    /**
     * 合并指定日期范围的访问统计
     */
    @PostMapping("/{id}/stats/merge")
    public Map<String, Object> mergeProductViewStats(@PathVariable Long id, @RequestBody List<String> dates) {
        return productViewService.mergeProductViewStats(id, dates.toArray(new String[0]));
    }

    /**
     * 清空商品访问统计
     */
    @DeleteMapping("/{id}/stats")
    public Map<String, Object> clearProductViewStats(@PathVariable Long id) {
        Map<String, Object> result = new HashMap<>();
        try {
            productViewService.clearProductViewStats(id);
            result.put("success", true);
            result.put("message", "清空成功");
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "清空失败: " + e.getMessage());
        }
        return result;
    }

    /**
     * 记录商品访问统计
     */
    private void recordProductView(Long productId, HttpServletRequest request) {
        try {
            // 获取用户标识（优先使用X-Real-IP，其次使用X-Forwarded-For，最后使用RemoteAddr）
            String userIdentifier = getUserIdentifier(request);

            // 获取会话标识（用于PV统计）
            String sessionId = request.getSession().getId();
            if (sessionId == null || sessionId.isEmpty()) {
                sessionId = UUID.randomUUID().toString();
            }

            // 异步记录访问统计，避免影响主业务性能
            String finalSessionId = sessionId;
            new Thread(() -> {
                try {
                    productViewService.recordProductView(productId, userIdentifier, finalSessionId);
                } catch (Exception e) {
                    // 在异步线程中记录错误，但不影响主流程
                    System.err.println("记录商品访问统计失败: " + e.getMessage());
                }
            }).start();

        } catch (Exception e) {
            // 记录访问统计失败不应影响主业务
            System.err.println("启动访问统计线程失败: " + e.getMessage());
        }
    }

    /**
     * 判断是否应该记录访问统计（排除管理端访问）
     */
    private boolean shouldRecordVisit(HttpServletRequest request) {
        // 方案1：通过请求头区分
        String clientType = request.getHeader("X-Client-Type");
        if ("admin".equalsIgnoreCase(clientType) || "management".equalsIgnoreCase(clientType)) {
            return false; // 管理端访问，不记录统计
        }

        // 方案2：通过User-Agent检测管理端工具
        String userAgent = request.getHeader("User-Agent");
        if (userAgent != null) {
            String userAgentLower = userAgent.toLowerCase();
            // 检测管理工具的User-Agent标识
            if (userAgentLower.contains("admin-tool") ||
                    userAgentLower.contains("management-system") ||
                    userAgentLower.contains("backend-admin")) {
                return false;
            }
        }

        // 方案3：通过特定参数排除
        String skipStats = request.getParameter("skipStats");
        if ("true".equalsIgnoreCase(skipStats)) {
            return false; // 明确指定跳过统计
        }

        return true; // 默认记录访问统计
    }

    /**
     * 获取用户标识（用于UV统计）
     */
    private String getUserIdentifier(HttpServletRequest request) {
        // 优先使用真实IP
        String realIp = request.getHeader("X-Real-IP");
        if (realIp != null && !realIp.isEmpty() && !"unknown".equalsIgnoreCase(realIp)) {
            return realIp;
        }

        // 其次使用转发IP
        String forwardedFor = request.getHeader("X-Forwarded-For");
        if (forwardedFor != null && !forwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(forwardedFor)) {
            // X-Forwarded-For可能包含多个IP，取第一个
            return forwardedFor.split(",")[0].trim();
        }

        // 最后使用远程地址
        String remoteAddr = request.getRemoteAddr();
        if (remoteAddr != null && !remoteAddr.isEmpty()) {
            return remoteAddr;
        }

        // 如果都获取不到，使用随机标识
        return "unknown_" + UUID.randomUUID().toString().substring(0, 8);
    }

    // 访问该接口，查看当前加载的流控规则
    @GetMapping("/sentinel/rules")
    public List<FlowRule> getFlowRules() {
        return FlowRuleManager.getRules(); // 获取Sentinel内存中的所有流控规则
    }
}
